import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.lang.reflect.InvocationTargetException;
import java.net.*;

@SuppressWarnings("serial")
public class Client extends UnicastRemoteObject implements Client_itf {

	private static Server_itf myServer;
	private static HashMap<Integer, SharedObject> sharedObjects = new HashMap<Integer, SharedObject>();
	private static Client_itf myClient;
	
	// debug
	public static String name = "";

	public String getName() {
		return name;
	}


	public Client() throws RemoteException {
		super();
	}


///////////////////////////////////////////////////
//         Interface to be used by applications
///////////////////////////////////////////////////

	// initialization of the client layer
	public static void init() {
		// recuperation du serveur distant
		try {
			myServer = (Server_itf) Naming.lookup("//localhost/myServer");
			myClient = new Client();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (NotBoundException e) {
			e.printStackTrace();
		}
	}// done
	
	// lookup in the name server
	public static SharedObject lookup(String name) {
		SharedObject sho = null;
		try {
			int id = myServer.lookup(name);
			if (id == -1) {
				sho = null;
			}
			else {			

				// -------------------------->  Ajout etape 2 <--------------------------
				Object o = myServer.getObjNotSynchronised(id);
				sho =Stub_Generateur.generer(o.getClass(),id,o);
				
				//sho = new SharedObject(id, null);
				sharedObjects.put(id, sho);	
				
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		return sho;
	}// done	
	
	// binding in the name server
	public static void register(String name, SharedObject_itf so) {
		int id = ((SharedObject) so).id;
		try {
			myServer.register(name, id);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}// done

	// creation of a shared object
	public static SharedObject create(Object o) {
		int id = -1;
		try {
			id = myServer.create(o);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		// -------------------------->  Ajout etape 2 <--------------------------
		SharedObject sho =Stub_Generateur.generer(o.getClass(),id,o);
		
		//SharedObject sho = new SharedObject(id, o);
		sharedObjects.put(new Integer(id), sho);		
		
		return sho;
	}
	
/////////////////////////////////////////////////////////////
//    Interface to be used by the consistency protocol
////////////////////////////////////////////////////////////

	// request a read lock from the server
	public static Object lock_read(int id) {
		Object o = null;
		try {
			o = myServer.lock_read(id, myClient);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		if (o == null) {
		}
		return o;
	}// done

	// request a write lock from the server
	public static Object lock_write (int id) {
		Object o = null;
		try {
			o = myServer.lock_write(id, myClient);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		if (o == null) {
		}
		return o;
	}// done

	// receive a lock reduction request from the server
	public Object reduce_lock(int id) throws java.rmi.RemoteException {
		return sharedObjects.get(id).reduce_lock();
	}// done


	// receive a reader invalidation request from the server
	public void invalidate_reader(int id) throws java.rmi.RemoteException {
		SharedObject sho = sharedObjects.get(id);
		sho.invalidate_reader();
	}// done


	// receive a writer invalidation request from the server
	public Object invalidate_writer(int id) throws java.rmi.RemoteException {
		return sharedObjects.get(id).invalidate_writer();
	}// done
}
